package com.hyt.it.ogt.kq.service.gov.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.exception.NestedBusinessException;
import com.hyt.it.ogt.kq.common.exception.GovInvalidRequestException;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.service.gov.mapper.OfficePlaceMapper;
import com.hyt.it.ogt.kq.service.gov.model.entity.OfficePlace;
import com.hyt.it.ogt.kq.service.gov.model.entity.OfficeRoom;
import com.hyt.it.ogt.kq.service.gov.model.param.OfficePlaceParam;
import com.hyt.it.ogt.kq.service.gov.model.vo.RoomPageVO;
import com.hyt.it.ogt.kq.service.gov.service.IOfficeCodeService;
import com.hyt.it.ogt.kq.service.gov.service.IOfficePlaceService;
import com.hyt.it.ogt.kq.service.gov.service.IOfficeRoomService;
import com.hyt.model.PageParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 考点信息表 服务实现类
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@Service
public class OfficePlaceServiceImpl extends BaseServiceImpl<OfficePlaceMapper, OfficePlace> implements IOfficePlaceService {

    @Autowired
    private IOfficeCodeService iOfficeCodeService;

    @Autowired
    private IOfficeRoomService iOfficeRoomService;

    @Autowired
    private OfficePlaceMapper officePlaceMapper;

    @Override
    @Transactional(rollbackFor = NestedBusinessException.class)
    public void add(OfficePlaceParam officePlaceParam, String officeId) throws GovInvalidRequestException {
        //校验添加考点参数
        this.checkPlaceByAdd(officePlaceParam, officeId);
        //设置考点信息基础字段
        OfficePlace officePlace = new OfficePlace();
        BeanUtils.copyProperties(officePlaceParam, officePlace);
        officePlace.setOfficeId(officeId)
            .setProvince(officePlaceParam.getProvinceId())
            .setCity(officePlaceParam.getCityId())
            .setDistrict(officePlaceParam.getDistrictId());
        //生成考点编号
        this.generatePlaceCode(officePlace);
        //插入机构考点模板表
        this.insertOfficePlace(officePlace);
    }

    @Override
    public List<Map<String, String>> getAll(String officeId, String areaId) {
        return officePlaceMapper.getAll(officeId, areaId);
    }

    @Override
    public Page<RoomPageVO> page(PageParam<RoomPageVO> pageParam, String officeId) {
        return officePlaceMapper.page(pageParam, officeId);
    }

    @Override
    @Transactional(rollbackFor = NestedBusinessException.class)
    public void update(OfficePlaceParam officePlaceParam, String officeId) throws GovInvalidRequestException {
        //校验更新考点参数
        OfficePlace currentOfficePlace = this.checkPlaceByUpdate(officePlaceParam, officeId);
        //更新机构考点信息
        this.updateOfficePlace(officePlaceParam, currentOfficePlace);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String placeId) {
        //删除考点信息
        baseMapper.deleteById(placeId);
        //删除考点下所有的考场信息
        QueryWrapper<OfficeRoom> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OfficeRoom::getPlaceId, placeId);
        iOfficeRoomService.remove(queryWrapper);

    }

    /**
     * 删除考点下所有的考场信息
     * @param placeId 考点id
     * @throws NestedBusinessException 删除失败，抛出异常
     */
    private void deleteRoomsByPlaceId(String placeId) throws NestedBusinessException {
        QueryWrapper<OfficeRoom> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OfficeRoom::getPlaceId, placeId);
        if (!iOfficeRoomService.remove(queryWrapper)) {
            throw new NestedBusinessException("删除机构考场信息模板表失败");
        }
    }

    /**
     * 删除考点信息
     * @param placeId 考点id
     * @throws NestedBusinessException 删除失败，抛出异常
     */
    private void deletePlace(String placeId) throws NestedBusinessException {
        if (!removeById(placeId)) {
            throw new NestedBusinessException("删除机构考点信息模板表失败");
        }
    }

    /**
     * 更新机构考点信息
     * @param officePlaceParam 更新考点参数
     * @param currentOfficePlace 待更新考点
     * @throws NestedBusinessException 更新失败，抛出异常
     */
    private void updateOfficePlace(OfficePlaceParam officePlaceParam, OfficePlace currentOfficePlace) throws NestedBusinessException {
        BeanUtils.copyProperties(officePlaceParam, currentOfficePlace);
        if (!updateById(currentOfficePlace)) {
            throw new NestedBusinessException("更新机构考点表失败");
        }
    }

    /**
     * 校验更新考点参数
     * @param officePlaceParam 更新考点参数
     * @param officeId 机构id
     * @return 待更新考点信息
     * @throws GovInvalidRequestException 校验不通过，抛出异常
     */
    private OfficePlace checkPlaceByUpdate(OfficePlaceParam officePlaceParam, String officeId) throws GovInvalidRequestException {
        //获取当前机构下所有考点
        QueryWrapper<OfficePlace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OfficePlace::getOfficeId, officeId)
                .eq(OfficePlace::getDelFlag, false);
        List<OfficePlace> officePlaceList = list(queryWrapper);
        //获取被编辑的考点
        OfficePlace currentOfficePlace = null;
        for (OfficePlace officePlace : officePlaceList) {
            if (officePlace.getId().equals(officePlaceParam.getId())) {
                currentOfficePlace = officePlace;
            }
        }
        if (ObjectUtils.isEmpty(currentOfficePlace)) {
            //当前考点已不存在
            throw new GovInvalidRequestException(ResponseCode.PLACE_QUERY_NON_EXISTENT.getCode(), ResponseCode.PLACE_QUERY_NON_EXISTENT.getMsg());
        }
        //编辑考点的情况下需要忽略被编辑的考点
        officePlaceList = officePlaceList.stream()
                .filter(officePlace -> !officePlace.getId().equals(officePlaceParam.getId()))
                .collect(Collectors.toList());
        //校验考点名称是否重复
        boolean repeat = officePlaceList.stream()
                .anyMatch(officePlace -> officePlace.getName().equals(officePlaceParam.getName()));
        if (repeat) {
            //当前机构下存在名称相同的考点
            throw new GovInvalidRequestException(ResponseCode.PLACE_ADD_NAME_REPEAT.getCode(), "当前机构下存在名称相同的考点");
        }
        return currentOfficePlace;
    }

    /**
     * 校验添加考点参数
     * @param officePlaceParam 添加考点参数
     * @param officeId 机构id
     * @throws GovInvalidRequestException 校验不通过，抛出异常
     */
    private void checkPlaceByAdd(OfficePlaceParam officePlaceParam, String officeId) throws GovInvalidRequestException {
        //获取当前机构下所有考点
        QueryWrapper<OfficePlace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OfficePlace::getOfficeId, officeId)
                .eq(OfficePlace::getDelFlag, false);
        List<OfficePlace> officePlaceList = list(queryWrapper);
        //校验考点名称是否重复
        if (!CollectionUtils.isEmpty(officePlaceList)) {
            String name = officePlaceParam.getName();
            boolean repeat = officePlaceList.stream()
                    .anyMatch(officePlace -> officePlace.getName().equals(name));
            if (repeat) {
                //当前机构下存在名称相同的考点
                throw new GovInvalidRequestException(ResponseCode.PLACE_ADD_NAME_REPEAT.getCode(),
                        ResponseCode.PLACE_ADD_NAME_REPEAT.getMsg());
            }
        }
    }

    /**
     * 插入机构考点模板表
     * @param officePlace 机构考点信息参数
     */
    private void insertOfficePlace(OfficePlace officePlace) throws NestedBusinessException {
        if (!save(officePlace)) {
            throw new NestedBusinessException("插入机构考点模板表失败");
        }
    }

    /**
     * 生成考点编号
     * 生成规则：机构系统编码(5位) + 自增序号
     * @param officePlace
     */
    @Override
    public void generatePlaceCode(OfficePlace officePlace) {
        Integer mapPlaceMaxSort = officePlaceMaxSort(officePlace.getOfficeId());
        //拼接自增序号
        officePlace.setCode(++mapPlaceMaxSort);
    }

    /**
     * 当前数据库中，考点对应的最大编号
     * @return
     */
    @Override
    public Integer officePlaceMaxSort(String officeId) {
        OfficePlace officePlace = this.lambdaQuery()
                .eq(OfficePlace::getOfficeId,officeId)
                .eq(OfficePlace::getDelFlag,false)
                .select(OfficePlace::getCode)
                .orderByDesc(OfficePlace::getCode)
                .last("limit 1").one();
        if (officePlace == null) {
            return 0;
        }

        return officePlace.getCode();
    }

}
